﻿using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Windows.Forms;
using VSMonitor.VSServiceReference;
using System.Threading;

namespace VSMonitor
{
    public partial class frmVSMonitor : Form
    {
        private VSServiceClient client;
        private DateTime lastRequest;
        private bool exit;

        public frmVSMonitor()
        {
            InitializeComponent();

            ShowMonitorMenuItem.Click += new EventHandler(ShowMonitorMenuItem_Click);
            ExitMenuItem.Click += new EventHandler(ExitMenuItem_Click);

            this.VSNotifyIcon.BalloonTipTitle = this.Text;
        }

        private void QueryTimer_Tick(object sender, EventArgs e)
        {
            if (Monitor.TryEnter(this))
            {
                client = new VSServiceClient();

                client.GetSessionsAsync();

                client.GetSessionsCompleted += (sender2, args) =>
                {
                    try
                    {
                        var sessions = args.Result;
                        var newItems = new List<VSServiceSession>();
                        var removedItems = new List<VSServiceSession>();
                        var balloonTip = new StringBuilder();

                        foreach (var session in sessions)
                        {
                            if (lstVSInstances.Items.Cast<ListViewItem>().Select(l => (VSServiceSession)l.Tag).Any(s => s.InstanceID == session.InstanceID || s.ProcessID == session.ProcessID))
                            {
                                // update existing items

                                var oldItems = lstVSInstances.Items.Cast<ListViewItem>().Where(l => ((VSServiceSession)l.Tag).InstanceID == session.InstanceID || ((VSServiceSession)l.Tag).ProcessID == session.ProcessID);

                                if (oldItems.Count() > 1)
                                {
                                    lstVSInstances.Items.Remove(oldItems.Single(l => ((VSServiceSession)l.Tag).ProcessID == 0));
                                    newItems.Add(session);
                                }

                                var oldItem = oldItems.Single();

                                oldItem.SubItems[0].Text = session.ProcessID.ToString();
                                oldItem.SubItems[1].Text = session.Title;
                                oldItem.SubItems[2].Text = session.UserID.ToString();
                                oldItem.SubItems[3].Text = session.IsRegistered ? "true" : "false";
                                oldItem.SubItems[4].Text = session.SessionOpened.ToString();
                                oldItem.SubItems[5].Text = session.VSInstanceOpened.ToString();
                                oldItem.SubItems[6].Text = session.VSInstanceRegistered.ToString();
                                oldItem.SubItems[7].Text = session.LastMessage.ToString();
                                oldItem.SubItems[8].Text = session.LastMessageRequest.ToString();
                            }
                            else
                            {
                                // not in list, add new

                                var item = new ListViewItem(session.ProcessID.ToString(), 0);

                                item.SubItems.AddRange(new ListViewItem.ListViewSubItem[]
                                {
                                    new ListViewItem.ListViewSubItem(item, session.Title),
                                    new ListViewItem.ListViewSubItem(item, session.UserID.ToString()),
                                    new ListViewItem.ListViewSubItem(item, session.IsRegistered ? "true" : "false"),
                                    new ListViewItem.ListViewSubItem(item, session.SessionOpened.ToString()),
                                    new ListViewItem.ListViewSubItem(item, session.VSInstanceOpened.ToString()),
                                    new ListViewItem.ListViewSubItem(item, session.VSInstanceRegistered.ToString()),
                                    new ListViewItem.ListViewSubItem(item, session.LastMessage.ToString()),
                                    new ListViewItem.ListViewSubItem(item, session.LastMessageRequest.ToString()),
                                });

                                item.Tag = session;

                                lstVSInstances.Items.Add(item);
                                newItems.Add(session);
                            }
                        }

                        // remove items no longer in list

                        if (lstVSInstances.Items.Cast<ListViewItem>().Any(l => !sessions.Any(s => ((VSServiceSession)l.Tag).ProcessID == s.ProcessID || ((VSServiceSession)l.Tag).InstanceID == s.InstanceID)))
                        {
                            var removed = lstVSInstances.Items.Cast<ListViewItem>().Where(l => !sessions.Any(s => ((VSServiceSession)l.Tag).ProcessID == s.ProcessID || ((VSServiceSession)l.Tag).InstanceID == s.InstanceID));

                            removed.ToList().ForEach(l => 
                                {
                                    removedItems.Add((VSServiceSession) l.Tag); 
                                    lstVSInstances.Items.Remove(l);
                                });
                        }

                        lastRequest = DateTime.Now;

                        StatusLabel.Text = "Connected - Last response: " + lastRequest.ToString();
                        StatusLabel.ForeColor = Color.Black;

                        if (newItems.Count > 0)
                        {
                            balloonTip.AppendLine("Added: \r\n");
                            newItems.ForEach(s => balloonTip.AppendLine(s.Title.Length > 0 ? s.Title : "ProcessID:" + s.ProcessID.ToString()));
                        }

                        if (removedItems.Count > 0)
                        {
                            if (newItems.Count > 0)
                            {
                                balloonTip.AppendLine("\r\n");
                            }

                            balloonTip.AppendLine("Removed: \r\n");
                            removedItems.ForEach(s => balloonTip.AppendLine(s.Title.Length > 0 ? s.Title : "ProcessID:" + s.ProcessID.ToString()));
                        }

                        if (balloonTip.Length > 0)
                        {
                            VSNotifyIcon.BalloonTipText = balloonTip.ToString();
                            VSNotifyIcon.ShowBalloonTip(5000);
                        }
                    }
                    catch (Exception ex)
                    {
                        if (!StatusLabel.Text.StartsWith("Disconnected"))
                        {
                            StatusLabel.Text = "Disconnected - Last response: " + lastRequest.ToString();
                            StatusLabel.ForeColor = Color.Red;
                        }
                    }

                    Monitor.Exit(this);
                };
            }

            Application.DoEvents();
        }

        private void ExitMenuItem_Click(object sender, EventArgs e)
        {
            VSNotifyIcon.Visible = false;
            exit = true;

            this.Close();
        }

        private void ShowMonitorMenuItem_Click(object sender, EventArgs e)
        {
            this.Show();
        }

        private void frmVSMonitor_FormClosing(object sender, FormClosingEventArgs e)
        {
            if (!exit)
            {
                e.Cancel = true;
                this.Hide();
            }
        }

        private void VSNotifyIcon_MouseDoubleClick(object sender, MouseEventArgs e)
        {
            this.Show();
        }

        private void frmVSMonitor_Resize(object sender, EventArgs e)
        {
            if (this.WindowState == FormWindowState.Minimized)
            {
                this.Hide();
            }
        }
    }
}
